#include <iostream>
#include <thread>

#include "c_input.h"
#include "component.h"
#include "entity.h"

volatile bool stop = false;

#define ComponentType(C, v) static int component_type() { return v; } virtual int type() { return C::component_type(); }
void proc_c(int id)
{
	CInputDeque inputDeque;
	while (!stop)
	{
		inputDeque.onTick(10);
		inputDeque.doPressW();
		inputDeque.doPressShoot();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}
struct BodyComponent : public BaseComponent
{
	ComponentType(BodyComponent, 2);
	BodyComponent(int entityID, int left, int top, int width, int height) :BaseComponent(entityID), m_left(left), m_top(top), m_width(width), m_height(height) {}

	int m_left, m_top, m_width, m_height, m_lastLeft, m_lastTop;
};
struct V2
{
	V2(int x, int y) :m_x(x), m_y(y) {}
	static V2 zero;
	int m_x, m_y;
};
V2 V2::zero = V2(0, 0);
Entity* e1;
Entity* e2;
struct MoveComponent : public BaseComponent
{
	ComponentType(MoveComponent, 1);
	MoveComponent(int entityID, int sx, int sy) :BaseComponent(entityID), m_speedX(sx), m_speedY(sy) {}

	int m_speedX, m_speedY;
};

struct MoveSystem : public SystemImpl
{
	virtual void update(EntityAdmin* ea, float delta) override
	{
		ea->each<MoveComponent, BodyComponent>([this, ea](MoveComponent*  mc, BodyComponent* bc)
		{
			bc->m_lastLeft = bc->m_left;
			bc->m_lastTop = bc->m_top;

			bc->m_left += mc->m_speedX;
			bc->m_top += mc->m_speedY;
			//std::cout << "System1 update" << entityID << std::endl;
		});
	}
};
struct CollisionSystem : public SystemImpl
{
	virtual void update(EntityAdmin* ea, float delta) override
	{
		BodyComponent* e1_bc = e1->component<BodyComponent>();
		BodyComponent* e2_bc = e2->component<BodyComponent>();
		std::cout << e1_bc->m_left << " " << e1_bc->m_top << std::endl;
		std::cout << e2_bc->m_left << " " << e2_bc->m_top << std::endl;
		int x1 = e1_bc->m_lastLeft;
		int y1 = e1_bc->m_lastTop;
		int x2 = e1_bc->m_left;
		int y2 = e1_bc->m_top;
		float x3 = e2_bc->m_left + e2_bc->m_width / 4.0;
		int y3 = e2_bc->m_top;
		int x4 = e2_bc->m_left + e2_bc->m_width;
		int y4 = y3;
		float m1 = (e1_bc->m_top - e1_bc->m_lastTop) / float(e1_bc->m_left - e1_bc->m_lastLeft);
		float m2 = (y4 - y3) / float(x4 - x3);
		float b1 = y1 - m1*x1;
		float b2 = y3 - m2*x3;
		float ix = (b2 - b1) / (m1 - m2);
		float iy = m1 * ix + b1;
		if (ix >= x3 && ix <= x4 && (e1_bc->m_top + e1_bc->m_height) >= y3 && (e1_bc->m_left + e1_bc->m_width) <= x4)
		{
			std::cout << "collision" << std::endl;
		}
	}
};


int main()
{
	EntityAdmin* ea = new EntityAdmin;

	ea->add_sys(new MoveSystem);
	ea->add_sys(new CollisionSystem);

	e1 = ea->create();
	e2 = ea->create();
	e1->assign<BodyComponent>(1, -25, 2, 4);
	e1->assign<MoveComponent>(6, 6);

	e2->assign<BodyComponent>(30, 4, 2, 4);
	e2->assign<MoveComponent>(0, 0);

	std::thread eaThread(std::bind([ea]() {
		while (!stop)
		{
			ea->updateFixed();
			std::this_thread::sleep_for(std::chrono::milliseconds(16));
		}
	}));

	//std::thread clientThread1(std::bind(proc_c, 1));
	//std::thread clientThread2(std::bind(proc_c, 2));
	//std::thread clientThread3(std::bind(proc_c, 3));

	std::cout << "press 'q' to exit" << std::endl;
	char c;
	while (1)
	{
		std::cin >> c;
		if (c == 'q')
			break;
	}
	stop = true;
	eaThread.join();

	//clientThread1.join();
	//clientThread2.join();
	//clientThread3.join();
	return 0;
}